﻿using DefaultDspPluginsLib;
using SoundEngine3.AudioProcessing;
using SoundEngine3.DspPlugins;
using SoundEngine3.DspPlugins.Meta;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using ZquenceStudio3.Core;
using ZquenceStudio3.Core.DspPlugins;
using ZquenceStudio3.DspPlugins;

namespace ZquenceStudio.DefaultDspPlugins.Effects
{
    public class Equalizer2Description : IDspPlugin
    {
        public DspPluginInfo GetDspPluginInfo()
        {
            return new DspPluginInfo("Equalizer2", DspType.Effect);
        }

        public BaseDspPluginInstance CreateDsp(ZquenceStudio3Context context, DspPluginInfo info)
        {
            return new Equalizer2(context, info);
        }
    }

    public class Equalizer2 : CoreDspEffectPlugin
    {
        private IntPtr mEqualizer2Ptr;
        private DefaultDspPluginsLib.Depricated.Effect_Equalizer2 mEqualizer2Cs;

        public struct Equalizer2Data
        {
            public int Channels;
            public int Length;
        }

#if !Portable
        [DllImport(NativeSoundEngineDllImport.Dll)]
        public static extern IntPtr Effect_Equalizer2_Create();

        [DllImport(NativeSoundEngineDllImport.Dll)]
        public static extern void Effect_Equalizer2_Delete(IntPtr ptr);

        [DllImport(NativeSoundEngineDllImport.Dll)]
        public static extern void Effect_Equalizer2_Setup(IntPtr ptr, int sampleRate, int outputChannels, double lowFreq, double highFreq, double band1, double band2, double band3);
        
        [DllImport(NativeSoundEngineDllImport.Dll)]
        public static extern void Effect_Equalizer2_Process(IntPtr reverbPtr, ref Equalizer2Data data,
            ref double wav_in_left, ref double wav_in_right, ref double wav_out_left, ref double wav_out_right);
#endif

        private double mBand1 = 1;
        private double mBand2 = 1;
        private double mBand3 = 1;
        private double mLowFrequency;
        private double mHighFrequency;

        public double Band1
        {
            get { return mBand1; }
            set
            {
                mBand1 = value;
                Update();
            }
        }
        public double Band2
        {
            get { return mBand2; }
            set
            {
                mBand2 = value;
                Update();
            }
        }
        public double Band3
        {
            get { return mBand3; }
            set
            {
                mBand3 = value;
                Update();
            }
        }
        public double LowFrequency
        {
            get { return mLowFrequency; }
            set
            {
                mLowFrequency = value;
                Update();
            }
        }
        public double HighFrequency
        {
            get { return mHighFrequency; }
            set
            {
                mHighFrequency = value;
                Update();
            }
        }

        private void Update()
        {
#if !Portable
            Effect_Equalizer2_Setup(mEqualizer2Ptr, (int)CoreContext.SoundEngine.SoundEngineContext.SampleRate, CoreContext.SoundEngine.SoundEngineContext.OutputChannels, mLowFrequency, mHighFrequency, mBand1, mBand2, mBand3);
#endif
            mEqualizer2Cs.Update((int)CoreContext.SoundEngine.SoundEngineContext.SampleRate, CoreContext.SoundEngine.SoundEngineContext.OutputChannels, mLowFrequency, mHighFrequency, mBand1, mBand2, mBand3);
        }

        public Equalizer2(ZquenceStudio3Context application, DspPluginInfo info)
            : base(application, info)
        {
#if !Portable
            mEqualizer2Ptr = Effect_Equalizer2_Create();
#endif
            mEqualizer2Cs = new DefaultDspPluginsLib.Depricated.Effect_Equalizer2();

            CreateParameters();

            Band1 = 1;
            Band2 = 1;
            Band3 = 1;
            LowFrequency = 850;
            HighFrequency = 0.7;

            SupportAudioProcessing = true;
        }

        ~Equalizer2()
        {
#if !Portable
            Effect_Equalizer2_Delete(mEqualizer2Ptr);
#endif
        }

        private void CreateParameters()
        {
            // Low.
            ParameterPropertiesDirect band1 = new ParameterPropertiesDirect(this);
            band1.Label = "Low";
            band1.DirectGet += delegate() { return Band1; };
            band1.DirectSet += delegate(double value) { Band1 = value; };
            band1.MinValue = 0;
            band1.MaxValue = 2;
            AddParameter(band1);

            // Mid.
            ParameterPropertiesDirect band2 = new ParameterPropertiesDirect(this);
            band2.Label = "Mid";
            band2.DirectGet += delegate() { return Band2; };
            band2.DirectSet += delegate(double value) { Band2 = value; };
            band2.MinValue = 0;
            band2.MaxValue = 2;
            AddParameter(band2);

            // Hi.
            ParameterPropertiesDirect band3 = new ParameterPropertiesDirect(this);
            band3.Label = "High";
            band3.DirectGet += delegate() { return Band3; };
            band3.DirectSet += delegate(double value) { Band3 = value; };
            band3.MinValue = 0;
            band3.MaxValue = 2;
            AddParameter(band3);

            // Low freq.
            ParameterPropertiesDirect lowFreq = new ParameterPropertiesDirect(this);
            lowFreq.Label = "Low freq";
            lowFreq.DirectGet += delegate() { return LowFrequency; };
            lowFreq.DirectSet += delegate(double value) { LowFrequency = value; };
            lowFreq.MinValue = 0;
            lowFreq.MaxValue = 2000;
            AddParameter(lowFreq);

            // High freq.
            ParameterPropertiesDirect highFreq = new ParameterPropertiesDirect(this);
            highFreq.Label = "High freq";
            highFreq.DirectGet += delegate() { return HighFrequency; };
            highFreq.DirectSet += delegate(double value) { HighFrequency = value; };
            highFreq.MinValue = 0.2;
            highFreq.MaxValue = 2;
            AddParameter(highFreq);

            Update();
        }
        
        public override Version Version
        {
            get { return DspPluginInfo.DefaultVersion; }
        }

        public override string PluginInfo
        {
            get { return DspPluginInfo.DefaultPluginInfo; }
        }
        
        public override void Process(BaseAudioBuffer input, BaseAudioBuffer output)
        {
            double[] wav_in_left = input.Channels[0].Samples;     // signal
            double[] wav_in_right = input.Channels[1].Samples;     // signal
            double[] wav_out_left = output.Channels[0].Samples;     // signal
            double[] wav_out_right = output.Channels[1].Samples;     // signal

            Equalizer2Data data;
            data.Channels = CoreContext.SoundEngine.SoundEngineContext.OutputChannels;
            data.Length = CoreContext.SoundEngine.SoundEngineContext.BufferSize;

            if (NativeSoundEngineDllImport.UseBenchmarking)
            {
                ZquenceStudio3.Core.Utils.ProfilerMeter.Start1("Equalizer2");
#if !Portable
                Effect_Equalizer2_Process(mEqualizer2Ptr, ref data, ref wav_in_left[0], ref wav_in_right[0], ref wav_out_left[0], ref wav_out_right[0]);
#endif
                ZquenceStudio3.Core.Utils.ProfilerMeter.Stop1("Equalizer2");
                ZquenceStudio3.Core.Utils.ProfilerMeter.Start2("Equalizer2");
                mEqualizer2Cs.Process(ref data, wav_in_left, wav_in_right, wav_out_left, wav_out_right);
                ZquenceStudio3.Core.Utils.ProfilerMeter.Stop2("Equalizer2");
            }
            else
            {
                if (NativeSoundEngineDllImport.UseNativeProcessing)
                {
#if !Portable
                    Effect_Equalizer2_Process(mEqualizer2Ptr, ref data, ref wav_in_left[0], ref wav_in_right[0], ref wav_out_left[0], ref wav_out_right[0]);
#endif
                }
                else
                {
                    mEqualizer2Cs.Process(ref data, wav_in_left, wav_in_right, wav_out_left, wav_out_right);
                }
            }
        }
        
        protected override void OnProcessEvents(List<SoundEngine3.MIDI.Meta.MidiMessage> midiMessages)
        {

        }
    }
}
